﻿//
// (C) Copyright 2009 Irantha Suwandarathna (iranthas@hotmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using EffiProz.Core.Navigators;
using EffiProz.Core.Errors;
using EffiProz.Core.RowIO;
using EffiProz.Core.Lib;
using EffiProz.Core.DataTypes;
using EffiProz.Core.Lib.IO;


namespace EffiProz.Core.Results
{
    public static class LobResultTypes
    {
        public const int REQUEST_GET_BYTES = 1;
        public const int REQUEST_SET_BYTES = 2;
        public const int REQUEST_GET_CHARS = 3;
        public const int REQUEST_SET_CHARS = 4;
        public const int REQUEST_GET_BYTE_PATTERN_POSITION = 5;
        public const int REQUEST_GET_CHAR_PATTERN_POSITION = 6;
        public const int REQUEST_CREATE_BYTES = 7;
        public const int REQUEST_CREATE_CHARS = 8;
        public const int REQUEST_TRUNCATE = 9;
        public const int REQUEST_GET_LENGTH = 10;
        public const int REQUEST_GET_LOB = 11;

        //
        public const int RESPONSE_GET_BYTES = 21;
        public const int RESPONSE_SET = 22;
        public const int RESPONSE_GET_CHARS = 23;
        public const int RESPONSE_GET_BYTE_PATTERN_POSITION = 25;
        public const int RESPONSE_GET_CHAR_PATTERN_POSITION = 26;
        public const int RESPONSE_CREATE_BYTES = 27;
        public const int RESPONSE_CREATE_CHARS = 28;
        public const int RESPONSE_TRUNCATE = 29;
    }

    public class ResultLob : Result
    {
        long lobID;
        int subType;
        long blockOffset;
        long blockLength;
        byte[] byteBlock;
        char[] charBlock;
        TextReader reader;
        Stream stream;

        private ResultLob()
        {
            mode = ResultConstants.LARGE_OBJECT_OP;
        }

        public static ResultLob newLobGetLengthRequest(long id)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_LENGTH;
            result.lobID = id;

            return result;
        }

        public static ResultLob newLobGetBytesRequest(long id, long offset,
                int length)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_BYTES;
            result.lobID = id;
            result.blockOffset = offset;
            result.blockLength = length;

            return result;
        }

        public static ResultLob newLobGetCharsRequest(long id, long offset,
                int length)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_CHARS;
            result.lobID = id;
            result.blockOffset = offset;
            result.blockLength = length;

            return result;
        }

        public static ResultLob newLobSetBytesRequest(long id, long offset,
                byte[] block)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_SET_BYTES;
            result.lobID = id;
            result.blockOffset = offset;
            result.byteBlock = block;
            result.blockLength = block.Length;

            return result;
        }

        public static ResultLob newLobSetCharsRequest(long id, long offset,
                char[] chars)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_SET_CHARS;
            result.lobID = id;
            result.blockOffset = offset;
            result.charBlock = chars;
            result.blockLength = chars.Length;

            return result;
        }

        public static ResultLob newLobTruncateRequest(long id, long offset)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_TRUNCATE;
            result.lobID = id;
            result.blockOffset = offset;

            return result;
        }

        public static ResultLob newLobGetBytesResponse(long id, long offset,
                byte[] block)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_GET_BYTES;
            result.lobID = id;
            result.blockOffset = offset;
            result.byteBlock = block;
            result.blockLength = block.Length;

            return result;
        }

        public static ResultLob newLobGetCharsResponse(long id, long offset,
                char[] chars)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_GET_CHARS;
            result.lobID = id;
            result.blockOffset = offset;
            result.charBlock = chars;
            result.blockLength = chars.Length;

            return result;
        }

        public static ResultLob newLobSetResponse(long id, long length)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_SET;
            result.lobID = id;
            result.blockLength = length;

            return result;
        }

        public static ResultLob newLobGetBytePatternPositionRequest(long id,
                byte[] pattern, long offset)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION;
            result.lobID = id;
            result.blockOffset = offset;
            result.byteBlock = pattern;
            result.blockLength = pattern.Length;

            return result;
        }

        public static ResultLob newLobGetCharPatternPositionRequest(long id,
                char[] pattern, long offset)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION;
            result.lobID = id;
            result.blockOffset = offset;
            result.charBlock = pattern;
            result.blockLength = pattern.Length;

            return result;
        }

        public static ResultLob newLobCreateBlobRequest(long sessionID,
                long lobID, Stream stream, long length)
        {

            ResultLob result = new ResultLob();

            result.lobID = lobID;
            result.subType = LobResultTypes.REQUEST_CREATE_BYTES;
            result.blockLength = length;
            result.stream = stream;

            return result;
        }

        public static ResultLob newLobCreateClobRequest(long sessionID,
                long lobID, TextReader reader, long length)
        {

            ResultLob result = new ResultLob();

            result.lobID = lobID;
            result.subType = LobResultTypes.REQUEST_CREATE_CHARS;
            result.blockLength = length;
            result.reader = reader;

            return result;
        }

        public static ResultLob newLobCreateBlobResponse(long id)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_CREATE_BYTES;
            result.lobID = id;

            return result;
        }

        public static ResultLob newLobCreateClobResponse(long id)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_CREATE_CHARS;
            result.lobID = id;

            return result;
        }

        public static ResultLob newLobTruncateResponse(long id)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.RESPONSE_TRUNCATE;
            result.lobID = id;

            return result;
        }

        public static ResultLob newLobGetRequest(long id, long offset,
                long length)
        {

            ResultLob result = new ResultLob();

            result.subType = LobResultTypes.REQUEST_GET_LOB;
            result.lobID = id;
            result.blockOffset = offset;
            result.blockLength = length;

            return result;
        }

        public static ResultLob newLob(DataInputStream dataInput,
                                       bool readTerminate)
        {

            ResultLob result = new ResultLob();         

            result.databaseID = dataInput.ReadInt();
            result.sessionID = dataInput.ReadLong();
            result.lobID = dataInput.ReadLong();
            result.subType = dataInput.ReadInt();

            switch (result.subType)
            {

                case LobResultTypes.REQUEST_CREATE_BYTES:
                case LobResultTypes.REQUEST_CREATE_CHARS:
                    result.blockOffset = dataInput.ReadInt();
                    result.blockLength = dataInput.ReadLong();
                    break;

                case LobResultTypes.REQUEST_GET_LOB:

                //
                case LobResultTypes.REQUEST_GET_BYTES:
                case LobResultTypes.REQUEST_GET_CHARS:
                    result.blockOffset = dataInput.ReadLong();
                    result.blockLength = dataInput.ReadLong();
                    break;

                case LobResultTypes.REQUEST_SET_BYTES:
                case LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION:
                    result.blockOffset = dataInput.ReadLong();
                    result.blockLength = dataInput.ReadLong();
                    result.byteBlock = new byte[(int)result.blockLength];

                    dataInput.Read(result.byteBlock, 0, (int)result.blockLength);
                    break;

                case LobResultTypes.REQUEST_SET_CHARS:
                case LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION:
                    result.blockOffset = dataInput.ReadLong();
                    result.blockLength = dataInput.ReadLong();
                    result.charBlock = new char[(int)result.blockLength];

                    for (int i = 0; i < result.charBlock.Length; i++)
                    {
                        result.charBlock[i] = dataInput.ReadChar();
                    }
                    break;

                case LobResultTypes.REQUEST_GET_LENGTH:
                case LobResultTypes.REQUEST_TRUNCATE:
                    result.blockOffset = dataInput.ReadLong();
                    break;

                case LobResultTypes.RESPONSE_GET_BYTES:
                    result.blockOffset = dataInput.ReadLong();
                    result.blockLength = dataInput.ReadLong();
                    result.byteBlock = new byte[(int)result.blockLength];

                    dataInput.Read(result.byteBlock, 0, (int)result.blockLength);
                    break;

                case LobResultTypes.RESPONSE_GET_CHARS:
                    result.blockOffset = dataInput.ReadLong();
                    result.blockLength = dataInput.ReadLong();
                    result.charBlock = new char[(int)result.blockLength];

                    for (int i = 0; i < result.charBlock.Length; i++)
                    {
                        result.charBlock[i] = dataInput.ReadChar();
                    }
                    break;

                case LobResultTypes.RESPONSE_SET:
                case LobResultTypes.RESPONSE_CREATE_BYTES:
                case LobResultTypes.RESPONSE_CREATE_CHARS:
                case LobResultTypes.RESPONSE_TRUNCATE:
                    result.blockLength = dataInput.ReadLong();
                    break;

                case LobResultTypes.RESPONSE_GET_BYTE_PATTERN_POSITION:
                case LobResultTypes.RESPONSE_GET_CHAR_PATTERN_POSITION:
                    result.blockOffset = dataInput.ReadLong();
                    break;

                default:
                    throw Error.runtimeError(ErrorCode.U_S0500, "ResultLob");
            }

            if (readTerminate)
            {
                dataInput.ReadByte();
            }

            return result;
        }

        public override void write(Stream dataOut,
                          RowOutputInterface rowOut)
        {

            writeBody(new DataOutputStream(dataOut));
            dataOut.WriteByte((byte)ResultConstants.NONE);
            dataOut.Flush();
        }

        public void writeBody(DataOutputStream dataOut)
        {

            dataOut.WriteByte((byte)mode);
            dataOut.WriteInt((int)databaseID);
            dataOut.WriteLong((long)sessionID);
            dataOut.WriteLong((long)lobID);
            dataOut.WriteInt((int)subType);
          
            switch (subType)
            {

                case LobResultTypes.REQUEST_CREATE_BYTES:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    dataOut.Write(stream, blockLength);
                    break;

                case LobResultTypes.REQUEST_CREATE_CHARS:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);                   
                    dataOut.Write(reader, blockLength);
                    break;

                case LobResultTypes.REQUEST_SET_BYTES:
                case LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    dataOut.Write(byteBlock);
                    break;

                case LobResultTypes.REQUEST_SET_CHARS:
                case LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    dataOut.WriteChars(charBlock);
                    break;

                case LobResultTypes.REQUEST_GET_LOB:

                //
                case LobResultTypes.REQUEST_GET_BYTES:
                case LobResultTypes.REQUEST_GET_CHARS:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    break;

                case LobResultTypes.REQUEST_GET_LENGTH:
                case LobResultTypes.REQUEST_TRUNCATE:
                    dataOut.WriteLong((long)blockOffset);
                    break;

                case LobResultTypes.RESPONSE_GET_BYTES:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    dataOut.Write(byteBlock);
                    break;

                case LobResultTypes.RESPONSE_GET_CHARS:
                    dataOut.WriteLong((long)blockOffset);
                    dataOut.WriteLong((long)blockLength);
                    dataOut.WriteChars(charBlock);
                    break;

                case LobResultTypes.RESPONSE_SET:
                case LobResultTypes.RESPONSE_CREATE_BYTES:
                case LobResultTypes.RESPONSE_CREATE_CHARS:
                case LobResultTypes.RESPONSE_TRUNCATE:
                    dataOut.WriteLong((long)blockLength);
                    break;

                case LobResultTypes.RESPONSE_GET_BYTE_PATTERN_POSITION:
                case LobResultTypes.RESPONSE_GET_CHAR_PATTERN_POSITION:
                    dataOut.WriteLong((long)blockOffset);
                    break;

                default:
                    throw Error.runtimeError(ErrorCode.U_S0500, "ResultLob");
            }
        }

        public long getLobID()
        {
            return lobID;
        }

        public int getSubType()
        {
            return subType;
        }

        public long getOffset()
        {
            return blockOffset;
        }

        public long getBlockLength()
        {
            return blockLength;
        }

        public byte[] getByteArray()
        {
            return byteBlock;
        }

        public char[] getCharArray()
        {
            return charBlock;
        }

        public Stream getInputStream()
        {
            return stream;
        }

        public TextReader getReader()
        {
            return reader;
        }
    }
}
